package com.yn.xgame;

import com.yn.xgame.message.Func1Message;
import com.yn.xgame.po.LoadInfo;
import com.yn.xgame.util.Utils;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.stream.Collectors;

/**
 * LoadInfoWatcher
 * Created by wangboo on 17/7/14.
 */
public class LoadInfoWatcher implements Watcher {

    private static final Logger logger = LoggerFactory.getLogger(LoadInfoWatcher.class);

    private ZkClient client;
    private String watchPath;
    private LoadInfoManager manager;
    private IServer server;

    public LoadInfoWatcher(ZkClient client, String watchPath, LoadInfoManager manager, IServer server) {
        this.client = client;
        this.watchPath = watchPath;
        this.manager = manager;
        this.server = server;
    }

    public void doWatch() {
        queryAllChildren();
    }

    private void queryAllChildren() {
        List<String> ids = client.getChildren(watchPath, this);
        logger.debug("{}: {}", watchPath, ids);
        if (ids.size() == 0) return;
        List<LoadInfo> list = ids.stream()
                .map(id -> client.getData(watchPath + "/" + id, LoadInfo.class))
                .collect(Collectors.toList());
        logger.debug("children: {}", list);
        server.pushMessage(new Func1Message<>(list, manager::reset));
    }

    @Override
    public void process(WatchedEvent event) {
        logger.debug("zk event: event: " + event);
        switch (event.getType()) {
            case None:
                if(event.getState() == Event.KeeperState.Disconnected) {
                    // 断开连接，重连尝试
                    client.reconnect();
                }
                break;
            case NodeChildrenChanged:
                if (watchPath.equals(event.getPath())) queryAllChildren();
                break;
            case NodeDeleted:
                if (event.getPath().startsWith(watchPath)) handleNodeDelete(event.getPath());
                break;
            case NodeDataChanged:
                if (event.getPath().startsWith(watchPath)) handleNodeUpdate(event.getPath());
                break;
        }
    }

    private void handleNodeUpdate(String path) {
        LoadInfo info = client.getData(path, LoadInfo.class);
        server.pushMessage(new Func1Message<>(info, manager::addOrUpdate));
    }

    private void handleNodeDelete(String path) {
        int no = Utils.getNo(path);
        server.pushMessage(new Func1Message<>(no, manager::remove));
    }
}
